CH04 - Over Fitting and model tunning
Modelos atuais conseguem representar quaisquer padrões nos dados, infelizmente eles podem over fitar (representar padrões que não são reproduziveis no decorrer do tempo), para avaliar modelos precisamos de uma metodologia sitemática. Nesse capítulo serão descritas técnicas para garantir um mesmo resultado para modelos no decorrer do tempo e evitar overfit. Nesse capítulo assume-se que os dados são representativos da população e que há uma qualidade mínima na proveniência de dados das amostras.
Com essas condições, nosso objetivo é tunar o modelo sem overfita-lo. Para tal dividimos o conjunto de dados em treino/teste, abordagens mais modernas dividem em vários conjuntos de treino/teste para atingir um resultado melhor do modelo.
The problem of over-fitting
Técnicas que aprendem muito bem a estrutura dos dados tão bem que ao ser aplicado nos dados onde o modelo foi construído prediz corretamente \(100%\) da amostra. Além de aprender os padrões gerais de comportamento dos dados o modelo aprendeu o ruído de cada dado, isso significa que o modelo overfitou
A figura acima, será usada para ilustrar o conceito de over-fitting, contém \(208\) exemplos e é um problema de classificação binária, com duas variáveis preditoras. Há um leve desbalanceamento nas classes \(111\) classe 1 e \(97\) classe 2 além disso existe uma sobreposição de classes, um problema tipicamente encontrado. Um modelo que use esses dados tem tipicamente um objetivo: predizer novos dados, o modelo pode ser representado como um fronteira(s) de decisão(ões).
A figura acima mostra dois possíveis modelos para solucionar esse problema, o primeiro separa cada conjunto de dados da classe 1 e alega que o restante seria da classe 2. Podemos perceber que esse padrão não é muito generalizável. O modelo da direita, apresenta uma fronteira de decisão menos rígida que não classifica corretamente todos os pontos, mas tem maior probabilidade de generalizar.
Nesse exmplo simplista, com apenas duas variáveis, é simples observar o over-fitting do modelo da esquerda. No mundo real modelos tem muitas outras variáveis tornando essa abordagem visual impraticável. Necessitamos de uma ferramenta para averiguar o grau de over-fitting.
Model tunning
Muitos modelos tem parâmetros impossíveis de serem estimados usando os dados, como o KNN, devemos informar o número de vizinhos. Ao escolher muitos vizinhos podemos não conseguir aprender o suficiente dos dados, ao escolher poucos podemos facilmente over-fittar. Esse tipo de parâmetro é conhecido por: parâmetro de tunning muitos modelos apresentam pelo menos um desses parâmetros. 
A escolha desses parâmetros aumentam ou reduzem o grau de especialização do modelo, podendo, causar over-fitting. POr exemplo o parâmetro custo do SVM C que informa o peso do erro de classificação do modelo, ao setar um valor grande para esse parâmetro, temos um modelo altamente over-fittado enquanto que um valor baixo indica um modelo com resultados baixos. No painel da direita da figura fronteiras de decisão foi escolhido um valor alto, no painel da esquerda foi escolhido um valor usando validação cruzada.
Uma abordagem para escolha de parâmetros é selecionar um subconjunto deles, treinar diversos modelos e observar o melhor entre eles. Esse processo pode ser visualizado na figura abaixo: 
Após selecionar um conjuntto de parâmetros aceitáveis para treinarmos o modelo devemos encontrar uma métrica (confiável) para avaliarmos sua performance. Nesse ponto aplicamos uma estratégia de força bruta nos dados e nos parâmetros para encontrarmos o melhor modelo e parâmetro. Outras abordagens para encontrar os parâmetros ótimo são usar algoritmos genéticos ou métodos de de busca baseados em simplex.
O maior problema é encontrar uma estimativa confiável para esses modelos e definir qual o melhor dentre eles, como vimos anteiormente taxa de erro pode nos levar a uma falsa sensação de segurança. Uma abordagem usada é testar o modelo para uma amostra não usada para treinar o mesmo, seu tamanho deve ser considerável.
Uma outra abordagem é usar um conjunto apenas de teste reamostrando o conjunto de treinamento, para realizar isso existem algumas técnicas estatísticas que serão abordadas adiante.
Divisão de dados
O coração do processo para encontrar os parâmetros ótimo é a divisão do conjunto de dados, a construção do modelo segue os seguintes passos:
- Pré-processamento dos preditores
- Estimação dos parâmetros
- Seleção de preditores
- Avaliação da performance
- Ajuste fino das regras de classificação (tipicamente usando curvas ROC)
Dado que há um conjunto fixo de pontos de amostra, o modelador deve decidir como distribui-los nessas etapas. A principal escolha são os pontos que serão usados para avaliar o modelo, idealmente não devem ser os mesmos usados para treinar/ajustar finamente o modelo, dessa forma, eles representam valores não viesados. Quando há um conjunto de dados grande e expressivo podemos separar os conjuntos em validação e teste sem problemas, usando um para treinar e outro para validar.
Quando não há um conjunto de dados grande o suficiente não fazemos um conjunto de validação pois cada instância deve ser usada para treinar o modelo. Além disso o conjunto de teste que seria usado pode não ter poder preditivo suficiente para tomar deciões precisas. Muitos pesquisadores reportaram que usar apenas um conjunto de dados é uma decisão pobre em termos de performance. Usar a validação cruzada é uma alternativa melhor e viável.
Se um conjunto de teste é estritamente necessário podemos tomar algumas ações:
- Podemos treinar o modelo com um conjunto e testar em outro
- No mundo de SPAM de e-mails os mais novos são mais importantes que os mais antigos.
Na maioria dos casos não há desejo em transformar os conjuntos de treino e teste em homogeneos, Amostragens aleatórias podem ser usadas para criar datasets equivalentes.
A forma mais simples para criar conjuntos de treino/teste é tomar amostras aleatórias, não considera informação sobre desbalanceamento entre classes, quando ocorre desbalancemento a distribuição entre classes do output do modelo pode variar muito entre o treino/teste.
Uma alternativa é usar uma amostragem estratificada ao separar os dados, que é uma amostra aleatória aplicada em subgrupos (acredito que aqui seja o upsampling e downsampling)
Os dados também podem ser divididos entre os valores das variáveis preditoras, uma proposta aceita na literatura é maximizar a dissimilaridade amostral. Há muitas formas para calcular a dissimilaridade amostral a mais comum é usar a distância entre dois pontos de um mesmo preditor, se a distância é pequena os pontos estão próximos, caso contrário estão longe (indicador de dissimilaridade). Para usar esse conceito como ferramenta suponha que o conjunto de teste foi inicializado com apenas uma instância. A dissimilaridade entre esse ponto e os pontos não alocados pode ser calculada. O ponto não alocado com maior dissimilaridade deve ser adicionado ao conjunto de teste. Para adicionar mais pontos será necessário um método para calcular a dissimilaridade entre um ponto e um conjunto, uma abordagem é usar o valor médio de dissimilaridade.
Calcula-se a dissimilaridade média dos pontos adicionados ao conjunto de dados, depois escolhemos o ponto (no conjunto não alocado) com maior dissmilaridade em relação a média de dissimilaridade do conjunto adicionado e adicionamos ele ao conjunto alocado esse processo continua até atingirmos o tamanho do conjunto de teste desejado.
A Figura abaixo mostra esse processo aplicado em um problema de classificação de dados, nesse tipo de problema a técnica de maximização é aplicada dentro de cada classe separadamente, nesse exemplo não foi usada a média entre grupos mas sim o mínimo.
Técnicas de reamostragem
De uma maneira geral técnicas de reamostragem usadas para avaliar a performance do modelo trabalham de forma parecida. Uma parte dos dados é usada para fitar o modelo e a outra é usada para testar a eficácia dos dados, esse processo é repetido diversas vezes os resultados são sumarizados e agregados. A diferença das tecnicas de reamostragem residem na forma como as subamostras são selecionados.
k-Fold Cross-validation
As instâncias são divididas em k partições com tamanhos aproximados, um modelo é fitado usando 9 partições e testado com a última. Esse processo é repetido 10 vezes trocando a partição de teste por uma que nunca foi usada para teste, na figura abaixo notamos um 3-fold cross-validation:
Uma variação dessa estratégia é fazer uma amostragem estratíficada por classes em cada um dos folds. Outra variação, leave one out cross-validation (LOOCV), é um caso especial onde k é igual ao número de instâncias, removemos uma e treinamos com as outras. O modelo final é calculado pela sumarização das k instâncias deixadas de fora uma a uma.
Não há definição formal sobre qual o melhor valor de k tipicamente são usados os valores \({5, 10}\) quanto maior o valor de k menor o bias da técnica. Com o aumento de k a diferença entre conjuntos de treino e teste reduz.
Um ponto importante sobre técnicas de reamostragem é incerteza (variação/ruído), um método sem viés pode predizer o valor correto mas paga um preço alto para isso, incerteza. O que significa que repetir o processo de re amostragem pode produzir resultados distintos. Validação cruzada possuí alta variação comparada a outras técnicas, porém para grandes conjuntos de treino essa variância pode ser desprezada.
Valores grandes de k são computacionalmente onerosos, LOOCV é o mais computacionalmente intenso dentre todas as técnicas pois necessita de um modelo distinto para cada ponto e cada subconjunto tem o tamanho da amostra menos um. Tem pesquisas que mostram que o leave one out é tão efetivo quanto uma validação cruzada para \(k=10\). Valores pequenos de k tem um bias alto mas são menos computacionalmente onerosos, esse bias é quase o mesmo obtido por um bootstrap porém com uma variância muito maior.
Generalizae Cross-validation
Para modelos lineares de regressão para aproximar o erro do leave-one-out. O generalized Cross-validation (GCV) estatística não exige refitar o modelo para cada subamostra \[
GCV = \frac{1}{n} \sum_{i=1}^{n} \frac{y_i - \hat{y_i}}{1 - \frac{df}{n}}
\] onde \(y_i\) é o i-ésimo rótulo, \(\hat{y_i}\) é a i-ésima predição do modelo e \(df\) são os graus de liberdade do modelo (parâmetros estimados pelo mesmo) que é uma medida de complexidade para modelos lineares. Dois modelos com a mesma soma de erro quadrado terão diferentes GCV se a complexidade dos modelos forem distintas. Vale ressaltar que é uma fórmula fechada.
Repeated Training/Test Splits
É conhecido por leave-group-out cross-validation, monte carlo cross-validation, cria muitas divisões dos dados de treino e teste, a proporção de dados para cada subamostra e o número de repetições são controlados pelo analista. Como falamos anteriormente, o bias reduz conforme a quantidade de dados na amostra se aproxima do conjunto de modelagem valores tipicamente usados são: 75% - 80% . A figura abaixo exemplifica esse esquema: 
Pode-se observar que a diferença fundamental entre essa estratégia e a validação cruzada é que pode haver repetição de instâncias podem ser representadas em vários grupos deixados para predizer. Além disso o número de repetições aqui tende a ser muito maior que uma validação cruzada.
O número e repetições é importante pois ao aumentarmos ele decrementamos a incerteza do modelo. Para resultados com alta instabilidade 20 repetições seriam suficientes, para obter um score mais estável podemos colocar 50-200 repetições. Esse valor é uma proporção dos exemplos sendo alocados no conjunto de predição, quanto maior a porcentagem mais repetições serão necessárias para reduzir a incerteza do modelo
Bootstrap
É uma amostragem com reposição, ou seja, após um ponto ser selecionado para o fold/set ele ainda fica disponível para ser reselecionado novamente. Uma amostra de bootstrap tem o mesmo tamanho do dataset original, como resultado direto alguns pontos serão selecionados mais de uma vez e outros não serão selecionados. Os pontos não selecionados são conhecidos por out-of-bag, uma iteração de bootstrap usa os exemplos selecionados para treinar o modelo e os out-of-bag para testar. Na figura abaixo podemos ver um exemplo disso:
De uma forma geral as taxas de erro de bootstrap tem menos incerteza que um k-fold, entretanto \(63.25\%\) dos pontos são representados pelo menos uma vez, portanto essa técnica tem um bias similar ao k-fold para \(k=2\). Se o conjunto de treino for pequeno esse bias é grande caso contrário pode ser desprezado.
LS0tCnRpdGxlOiAiRGF0YSBQcmUtcHJvY2Vzc2luZyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBDSDA0IC0gT3ZlciBGaXR0aW5nIGFuZCBtb2RlbCB0dW5uaW5nCk1vZGVsb3MgYXR1YWlzIGNvbnNlZ3VlbSByZXByZXNlbnRhciBxdWFpc3F1ZXIgcGFkcsO1ZXMgbm9zIGRhZG9zLCBpbmZlbGl6bWVudGUgZWxlcyBwb2RlbSBvdmVyIGZpdGFyIChyZXByZXNlbnRhciBwYWRyw7VlcyBxdWUgbsOjbyBzw6NvIHJlcHJvZHV6aXZlaXMgbm8gZGVjb3JyZXIgZG8gdGVtcG8pLCBwYXJhIGF2YWxpYXIgbW9kZWxvcyBwcmVjaXNhbW9zIGRlIHVtYSBtZXRvZG9sb2dpYSBzaXRlbcOhdGljYS4gTmVzc2UgY2Fww610dWxvIHNlcsOjbyBkZXNjcml0YXMgdMOpY25pY2FzIHBhcmEgZ2FyYW50aXIgdW0gbWVzbW8gcmVzdWx0YWRvIHBhcmEgbW9kZWxvcyBubyBkZWNvcnJlciBkbyB0ZW1wbyBlIGV2aXRhciBvdmVyZml0LiBOZXNzZSBjYXDDrXR1bG8gYXNzdW1lLXNlIHF1ZSBvcyBkYWRvcyBzw6NvIHJlcHJlc2VudGF0aXZvcyBkYSBwb3B1bGHDp8OjbyBlIHF1ZSBow6EgdW1hIHF1YWxpZGFkZSBtw61uaW1hIG5hIHByb3ZlbmnDqm5jaWEgZGUgZGFkb3MgZGFzIGFtb3N0cmFzLgoKQ29tIGVzc2FzIGNvbmRpw6fDtWVzLCBub3NzbyBvYmpldGl2byDDqSB0dW5hciBvIG1vZGVsbyBzZW0gb3ZlcmZpdGEtbG8uIFBhcmEgdGFsIGRpdmlkaW1vcyBvIGNvbmp1bnRvIGRlIGRhZG9zIGVtIHRyZWluby90ZXN0ZSwgYWJvcmRhZ2VucyBtYWlzIG1vZGVybmFzIGRpdmlkZW0gZW0gdsOhcmlvcyBjb25qdW50b3MgZGUgdHJlaW5vL3Rlc3RlIHBhcmEgYXRpbmdpciB1bSByZXN1bHRhZG8gbWVsaG9yIGRvIG1vZGVsby4KCiMjI1RoZSBwcm9ibGVtIG9mIG92ZXItZml0dGluZwpUw6ljbmljYXMgcXVlIGFwcmVuZGVtIG11aXRvIGJlbSBhIGVzdHJ1dHVyYSBkb3MgZGFkb3MgdMOjbyBiZW0gcXVlIGFvIHNlciBhcGxpY2FkbyBub3MgZGFkb3Mgb25kZSBvIG1vZGVsbyBmb2kgY29uc3RydcOtZG8gcHJlZGl6IGNvcnJldGFtZW50ZSAkMTAwJSQgZGEgYW1vc3RyYS4gQWzDqW0gZGUgYXByZW5kZXIgb3MgcGFkcsO1ZXMgZ2VyYWlzIGRlIGNvbXBvcnRhbWVudG8gZG9zIGRhZG9zIG8gbW9kZWxvIGFwcmVuZGV1IG8gcnXDrWRvIGRlIGNhZGEgZGFkbywgaXNzbyBzaWduaWZpY2EgcXVlIG8gbW9kZWxvICpvdmVyZml0b3UqIAoKIVtDb25qdW50byBkZSB0cmVpbm8gY29tIGRvaXMgcHJlZGl0b3Jlc10oLi9DaDA0RmlnMDEucG5nKQoKQSBmaWd1cmEgYWNpbWEsIHNlcsOhIHVzYWRhIHBhcmEgaWx1c3RyYXIgbyBjb25jZWl0byBkZSBvdmVyLWZpdHRpbmcsIGNvbnTDqW0gJDIwOCQgZXhlbXBsb3MgZSDDqSB1bSBwcm9ibGVtYSBkZSBjbGFzc2lmaWNhw6fDo28gYmluw6FyaWEsIGNvbSBkdWFzIHZhcmnDoXZlaXMgcHJlZGl0b3Jhcy4gSMOhIHVtIGxldmUgZGVzYmFsYW5jZWFtZW50byBuYXMgY2xhc3NlcyAkMTExJCBjbGFzc2UgMSBlICQ5NyQgY2xhc3NlIDIgYWzDqW0gZGlzc28gZXhpc3RlIHVtYSBzb2JyZXBvc2nDp8OjbyBkZSBjbGFzc2VzLCB1bSBwcm9ibGVtYSB0aXBpY2FtZW50ZSBlbmNvbnRyYWRvLiBVbSBtb2RlbG8gcXVlIHVzZSBlc3NlcyBkYWRvcyB0ZW0gdGlwaWNhbWVudGUgdW0gb2JqZXRpdm86ICpwcmVkaXplciBub3ZvcyBkYWRvcyosIG8gbW9kZWxvIHBvZGUgc2VyIHJlcHJlc2VudGFkbyBjb21vIHVtIGZyb250ZWlyYShzKSBkZSBkZWNpc8OjbyjDtWVzKS4KCiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDIucG5nKQoKQSBmaWd1cmEgYWNpbWEgbW9zdHJhIGRvaXMgcG9zc8OtdmVpcyBtb2RlbG9zIHBhcmEgc29sdWNpb25hciBlc3NlIHByb2JsZW1hLCBvIHByaW1laXJvIHNlcGFyYSBjYWRhIGNvbmp1bnRvIGRlIGRhZG9zIGRhIGNsYXNzZSAxIGUgYWxlZ2EgcXVlIG8gcmVzdGFudGUgc2VyaWEgZGEgY2xhc3NlIDIuIFBvZGVtb3MgcGVyY2ViZXIgcXVlIGVzc2UgcGFkcsOjbyBuw6NvIMOpIG11aXRvIGdlbmVyYWxpesOhdmVsLiBPIG1vZGVsbyBkYSBkaXJlaXRhLCBhcHJlc2VudGEgdW1hIGZyb250ZWlyYSBkZSBkZWNpc8OjbyBtZW5vcyByw61naWRhIHF1ZSBuw6NvIGNsYXNzaWZpY2EgY29ycmV0YW1lbnRlIHRvZG9zIG9zIHBvbnRvcywgbWFzIHRlbSBtYWlvciBwcm9iYWJpbGlkYWRlIGRlIGdlbmVyYWxpemFyLgoKTmVzc2UgZXhtcGxvIHNpbXBsaXN0YSwgY29tIGFwZW5hcyBkdWFzIHZhcmnDoXZlaXMsIMOpIHNpbXBsZXMgb2JzZXJ2YXIgbyBvdmVyLWZpdHRpbmcgZG8gbW9kZWxvIGRhIGVzcXVlcmRhLiBObyBtdW5kbyByZWFsIG1vZGVsb3MgdGVtIG11aXRhcyBvdXRyYXMgdmFyacOhdmVpcyB0b3JuYW5kbyBlc3NhIGFib3JkYWdlbSB2aXN1YWwgaW1wcmF0aWPDoXZlbC4gTmVjZXNzaXRhbW9zIGRlIHVtYSBmZXJyYW1lbnRhIHBhcmEgYXZlcmlndWFyIG8gZ3JhdSBkZSBvdmVyLWZpdHRpbmcuCgojIyNNb2RlbCB0dW5uaW5nCk11aXRvcyBtb2RlbG9zIHRlbSBwYXLDom1ldHJvcyBpbXBvc3PDrXZlaXMgZGUgc2VyZW0gZXN0aW1hZG9zIHVzYW5kbyBvcyBkYWRvcywgY29tbyBvIEtOTiwgZGV2ZW1vcyBpbmZvcm1hciBvIG7Dum1lcm8gZGUgdml6aW5ob3MuIEFvIGVzY29saGVyIG11aXRvcyB2aXppbmhvcyBwb2RlbW9zIG7Do28gY29uc2VndWlyIGFwcmVuZGVyIG8gc3VmaWNpZW50ZSBkb3MgZGFkb3MsIGFvIGVzY29saGVyIHBvdWNvcyBwb2RlbW9zIGZhY2lsbWVudGUgb3Zlci1maXR0YXIuIEVzc2UgdGlwbyBkZSBwYXLDom1ldHJvIMOpIGNvbmhlY2lkbyBwb3I6ICpwYXLDom1ldHJvIGRlIHR1bm5pbmcqIG11aXRvcyBtb2RlbG9zIGFwcmVzZW50YW0gcGVsbyBtZW5vcyB1bSBkZXNzZXMgcGFyw6JtZXRyb3MuCiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDMucG5nKQoKQSBlc2NvbGhhIGRlc3NlcyBwYXLDom1ldHJvcyBhdW1lbnRhbSBvdSByZWR1emVtIG8gZ3JhdSBkZSBlc3BlY2lhbGl6YcOnw6NvIGRvIG1vZGVsbywgcG9kZW5kbywgY2F1c2FyIG92ZXItZml0dGluZy4gUE9yIGV4ZW1wbG8gbyBwYXLDom1ldHJvIGN1c3RvIGRvIFNWTSAqQyogcXVlIGluZm9ybWEgbyBwZXNvIGRvIGVycm8gZGUgY2xhc3NpZmljYcOnw6NvIGRvIG1vZGVsbywgYW8gc2V0YXIgdW0gdmFsb3IgZ3JhbmRlIHBhcmEgZXNzZSBwYXLDom1ldHJvLCB0ZW1vcyB1bSBtb2RlbG8gYWx0YW1lbnRlIG92ZXItZml0dGFkbyBlbnF1YW50byBxdWUgdW0gdmFsb3IgYmFpeG8gaW5kaWNhIHVtIG1vZGVsbyBjb20gcmVzdWx0YWRvcyBiYWl4b3MuIE5vIHBhaW5lbCBkYSBkaXJlaXRhIGRhIGZpZ3VyYSBmcm9udGVpcmFzIGRlIGRlY2lzw6NvIGZvaSBlc2NvbGhpZG8gdW0gdmFsb3IgYWx0bywgbm8gcGFpbmVsIGRhIGVzcXVlcmRhIGZvaSBlc2NvbGhpZG8gdW0gdmFsb3IgdXNhbmRvIHZhbGlkYcOnw6NvIGNydXphZGEuCgpVbWEgYWJvcmRhZ2VtIHBhcmEgZXNjb2xoYSBkZSBwYXLDom1ldHJvcyDDqSBzZWxlY2lvbmFyIHVtIHN1YmNvbmp1bnRvIGRlbGVzLCB0cmVpbmFyIGRpdmVyc29zIG1vZGVsb3MgZSBvYnNlcnZhciBvIG1lbGhvciBlbnRyZSBlbGVzLgpFc3NlIHByb2Nlc3NvIHBvZGUgc2VyIHZpc3VhbGl6YWRvIG5hIGZpZ3VyYSBhYmFpeG86CiFbRnJvbnRlaXJhcyBkZSBkZWNpc8Ojb10oLi9DaDA0RmlnMDQucG5nKQoKCkFww7NzIHNlbGVjaW9uYXIgdW0gY29uanVudHRvIGRlIHBhcsOibWV0cm9zIGFjZWl0w6F2ZWlzIHBhcmEgdHJlaW5hcm1vcyBvIG1vZGVsbyBkZXZlbW9zIGVuY29udHJhciB1bWEgbcOpdHJpY2EgKGNvbmZpw6F2ZWwpIHBhcmEgYXZhbGlhcm1vcyBzdWEgcGVyZm9ybWFuY2UuIE5lc3NlIHBvbnRvIGFwbGljYW1vcyB1bWEgZXN0cmF0w6lnaWEgZGUgZm9yw6dhIGJydXRhIG5vcyBkYWRvcyBlIG5vcyBwYXLDom1ldHJvcyBwYXJhIGVuY29udHJhcm1vcyBvIG1lbGhvciBtb2RlbG8gZSBwYXLDom1ldHJvLiBPdXRyYXMgYWJvcmRhZ2VucyBwYXJhIGVuY29udHJhciBvcyBwYXLDom1ldHJvcyDDs3RpbW8gc8OjbyB1c2FyIGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcyBvdSBtw6l0b2RvcyBkZSBkZSBidXNjYSBiYXNlYWRvcyBlbSBzaW1wbGV4LgoKTyBtYWlvciBwcm9ibGVtYSDDqSBlbmNvbnRyYXIgdW1hIGVzdGltYXRpdmEgY29uZmnDoXZlbCBwYXJhIGVzc2VzIG1vZGVsb3MgZSBkZWZpbmlyIHF1YWwgbyBtZWxob3IgZGVudHJlIGVsZXMsIGNvbW8gdmltb3MgYW50ZWlvcm1lbnRlIHRheGEgZGUgZXJybyBwb2RlIG5vcyBsZXZhciBhIHVtYSBmYWxzYSBzZW5zYcOnw6NvIGRlIHNlZ3VyYW7Dp2EuIFVtYSBhYm9yZGFnZW0gdXNhZGEgw6kgdGVzdGFyIG8gbW9kZWxvIHBhcmEgdW1hIGFtb3N0cmEgbsOjbyB1c2FkYSBwYXJhIHRyZWluYXIgbyBtZXNtbywgc2V1IHRhbWFuaG8gZGV2ZSBzZXIgY29uc2lkZXLDoXZlbC4KClVtYSBvdXRyYSBhYm9yZGFnZW0gw6kgdXNhciB1bSBjb25qdW50byBhcGVuYXMgZGUgdGVzdGUgcmVhbW9zdHJhbmRvIG8gY29uanVudG8gZGUgdHJlaW5hbWVudG8sIHBhcmEgcmVhbGl6YXIgaXNzbyBleGlzdGVtIGFsZ3VtYXMgdMOpY25pY2FzIGVzdGF0w61zdGljYXMgcXVlIHNlcsOjbyBhYm9yZGFkYXMgYWRpYW50ZS4KCgojIyNEaXZpc8OjbyBkZSBkYWRvcwpPIGNvcmHDp8OjbyBkbyBwcm9jZXNzbyBwYXJhIGVuY29udHJhciBvcyBwYXLDom1ldHJvcyDDs3RpbW8gw6kgYSBkaXZpc8OjbyBkbyBjb25qdW50byBkZSBkYWRvcywgYSBjb25zdHJ1w6fDo28gZG8gbW9kZWxvIHNlZ3VlIG9zIHNlZ3VpbnRlcyBwYXNzb3M6CgoxLiBQcsOpLXByb2Nlc3NhbWVudG8gZG9zIHByZWRpdG9yZXMKMi4gRXN0aW1hw6fDo28gZG9zIHBhcsOibWV0cm9zCjMuIFNlbGXDp8OjbyBkZSBwcmVkaXRvcmVzCjQuIEF2YWxpYcOnw6NvIGRhIHBlcmZvcm1hbmNlCjUuIEFqdXN0ZSBmaW5vIGRhcyByZWdyYXMgZGUgY2xhc3NpZmljYcOnw6NvICh0aXBpY2FtZW50ZSB1c2FuZG8gY3VydmFzIFJPQykKCkRhZG8gcXVlIGjDoSB1bSBjb25qdW50byBmaXhvIGRlIHBvbnRvcyBkZSBhbW9zdHJhLCBvIG1vZGVsYWRvciBkZXZlIGRlY2lkaXIgY29tbyBkaXN0cmlidWktbG9zIG5lc3NhcyBldGFwYXMuIEEgcHJpbmNpcGFsIGVzY29saGEgc8OjbyBvcyBwb250b3MgcXVlIHNlcsOjbyB1c2Fkb3MgcGFyYSBhdmFsaWFyIG8gbW9kZWxvLCBpZGVhbG1lbnRlIG7Do28gZGV2ZW0gc2VyIG9zIG1lc21vcyB1c2Fkb3MgcGFyYSB0cmVpbmFyL2FqdXN0YXIgZmluYW1lbnRlIG8gbW9kZWxvLCBkZXNzYSBmb3JtYSwgZWxlcyByZXByZXNlbnRhbSB2YWxvcmVzIG7Do28gdmllc2Fkb3MuIFF1YW5kbyBow6EgdW0gY29uanVudG8gZGUgZGFkb3MgZ3JhbmRlIGUgZXhwcmVzc2l2byBwb2RlbW9zIHNlcGFyYXIgb3MgY29uanVudG9zIGVtIHZhbGlkYcOnw6NvIGUgdGVzdGUgc2VtIHByb2JsZW1hcywgdXNhbmRvIHVtIHBhcmEgKnRyZWluYXIqIGUgb3V0cm8gcGFyYSAqdmFsaWRhciouCgpRdWFuZG8gbsOjbyBow6EgdW0gY29uanVudG8gZGUgZGFkb3MgZ3JhbmRlIG8gc3VmaWNpZW50ZSBuw6NvIGZhemVtb3MgdW0gY29uanVudG8gZGUgdmFsaWRhw6fDo28gcG9pcyBjYWRhIGluc3TDom5jaWEgZGV2ZSBzZXIgdXNhZGEgcGFyYSB0cmVpbmFyIG8gbW9kZWxvLiBBbMOpbSBkaXNzbyBvIGNvbmp1bnRvIGRlIHRlc3RlIHF1ZSBzZXJpYSB1c2FkbyBwb2RlIG7Do28gdGVyIHBvZGVyIHByZWRpdGl2byBzdWZpY2llbnRlIHBhcmEgdG9tYXIgZGVjacO1ZXMgcHJlY2lzYXMuIE11aXRvcyBwZXNxdWlzYWRvcmVzIHJlcG9ydGFyYW0gcXVlIHVzYXIgYXBlbmFzIHVtIGNvbmp1bnRvIGRlIGRhZG9zIMOpIHVtYSBkZWNpc8OjbyBwb2JyZSBlbSB0ZXJtb3MgZGUgcGVyZm9ybWFuY2UuIFVzYXIgYSB2YWxpZGHDp8OjbyBjcnV6YWRhIMOpIHVtYSBhbHRlcm5hdGl2YSBtZWxob3IgZSB2acOhdmVsLgoKU2UgdW0gY29uanVudG8gZGUgdGVzdGUgw6kgZXN0cml0YW1lbnRlIG5lY2Vzc8OhcmlvIHBvZGVtb3MgdG9tYXIgYWxndW1hcyBhw6fDtWVzOgoKMS4gUG9kZW1vcyB0cmVpbmFyIG8gbW9kZWxvIGNvbSB1bSBjb25qdW50byBlIHRlc3RhciBlbSBvdXRybwoyLiBObyBtdW5kbyBkZSBTUEFNIGRlIGUtbWFpbHMgb3MgbWFpcyBub3ZvcyBzw6NvIG1haXMgaW1wb3J0YW50ZXMgcXVlIG9zIG1haXMgYW50aWdvcy4KCk5hIG1haW9yaWEgZG9zIGNhc29zIG7Do28gaMOhIGRlc2VqbyBlbSB0cmFuc2Zvcm1hciBvcyBjb25qdW50b3MgZGUgdHJlaW5vIGUgdGVzdGUgZW0gaG9tb2dlbmVvcywgQW1vc3RyYWdlbnMgYWxlYXTDs3JpYXMgcG9kZW0gc2VyIHVzYWRhcyBwYXJhIGNyaWFyIGRhdGFzZXRzIGVxdWl2YWxlbnRlcy4KCkEgZm9ybWEgbWFpcyBzaW1wbGVzIHBhcmEgY3JpYXIgY29uanVudG9zIGRlIHRyZWluby90ZXN0ZSDDqSB0b21hciBhbW9zdHJhcyBhbGVhdMOzcmlhcywgbsOjbyBjb25zaWRlcmEgaW5mb3JtYcOnw6NvIHNvYnJlIGRlc2JhbGFuY2VhbWVudG8gZW50cmUgY2xhc3NlcywgcXVhbmRvIG9jb3JyZSBkZXNiYWxhbmNlbWVudG8gYSBkaXN0cmlidWnDp8OjbyBlbnRyZSBjbGFzc2VzIGRvIG91dHB1dCBkbyBtb2RlbG8gcG9kZSB2YXJpYXIgbXVpdG8gZW50cmUgbyB0cmVpbm8vdGVzdGUuCgpVbWEgYWx0ZXJuYXRpdmEgw6kgdXNhciB1bWEgYW1vc3RyYWdlbSBlc3RyYXRpZmljYWRhIGFvIHNlcGFyYXIgb3MgZGFkb3MsIHF1ZSDDqSB1bWEgYW1vc3RyYSBhbGVhdMOzcmlhIGFwbGljYWRhIGVtIHN1YmdydXBvcyAoYWNyZWRpdG8gcXVlIGFxdWkgc2VqYSBvIHVwc2FtcGxpbmcgZSBkb3duc2FtcGxpbmcpCgpPcyBkYWRvcyAgdGFtYsOpbSBwb2RlbSBzZXIgZGl2aWRpZG9zIGVudHJlIG9zIHZhbG9yZXMgZGFzIHZhcmnDoXZlaXMgcHJlZGl0b3JhcywgdW1hIHByb3Bvc3RhIGFjZWl0YSBuYSBsaXRlcmF0dXJhIMOpIG1heGltaXphciBhIGRpc3NpbWlsYXJpZGFkZSBhbW9zdHJhbC4gSMOhIG11aXRhcyBmb3JtYXMgcGFyYSBjYWxjdWxhciBhIGRpc3NpbWlsYXJpZGFkZSBhbW9zdHJhbCBhIG1haXMgY29tdW0gw6kgdXNhciBhIGRpc3TDom5jaWEgZW50cmUgZG9pcyBwb250b3MgZGUgdW0gbWVzbW8gcHJlZGl0b3IsIHNlIGEgZGlzdMOibmNpYSDDqSBwZXF1ZW5hIG9zIHBvbnRvcyBlc3TDo28gcHLDs3hpbW9zLCBjYXNvIGNvbnRyw6FyaW8gZXN0w6NvIGxvbmdlIChpbmRpY2Fkb3IgZGUgZGlzc2ltaWxhcmlkYWRlKS4gUGFyYSB1c2FyIGVzc2UgY29uY2VpdG8gY29tbyBmZXJyYW1lbnRhIHN1cG9uaGEgcXVlIG8gY29uanVudG8gZGUgdGVzdGUgZm9pIGluaWNpYWxpemFkbyBjb20gYXBlbmFzIHVtYSBpbnN0w6JuY2lhLiBBIGRpc3NpbWlsYXJpZGFkZSBlbnRyZSBlc3NlIHBvbnRvIGUgb3MgcG9udG9zIG7Do28gYWxvY2Fkb3MgcG9kZSBzZXIgY2FsY3VsYWRhLiBPIHBvbnRvIG7Do28gYWxvY2FkbyBjb20gbWFpb3IgZGlzc2ltaWxhcmlkYWRlIGRldmUgc2VyIGFkaWNpb25hZG8gYW8gY29uanVudG8gZGUgdGVzdGUuIFBhcmEgYWRpY2lvbmFyIG1haXMgcG9udG9zIHNlcsOhIG5lY2Vzc8OhcmlvIHVtIG3DqXRvZG8gcGFyYSBjYWxjdWxhciBhIGRpc3NpbWlsYXJpZGFkZSBlbnRyZSB1bSBwb250byBlIHVtIGNvbmp1bnRvLCB1bWEgYWJvcmRhZ2VtIMOpIHVzYXIgbyB2YWxvciBtw6lkaW8gZGUgZGlzc2ltaWxhcmlkYWRlLgoKQ2FsY3VsYS1zZSBhIGRpc3NpbWlsYXJpZGFkZSBtw6lkaWEgZG9zIHBvbnRvcyBhZGljaW9uYWRvcyBhbyBjb25qdW50byBkZSBkYWRvcywgZGVwb2lzIGVzY29saGVtb3MgbyBwb250byAobm8gY29uanVudG8gbsOjbyBhbG9jYWRvKSBjb20gbWFpb3IgZGlzc21pbGFyaWRhZGUgZW0gcmVsYcOnw6NvIGEgbcOpZGlhIGRlIGRpc3NpbWlsYXJpZGFkZSBkbyBjb25qdW50byBhZGljaW9uYWRvIGUgYWRpY2lvbmFtb3MgZWxlIGFvIGNvbmp1bnRvIGFsb2NhZG8gZXNzZSBwcm9jZXNzbyBjb250aW51YSBhdMOpIGF0aW5naXJtb3MgbyB0YW1hbmhvIGRvIGNvbmp1bnRvIGRlIHRlc3RlIGRlc2VqYWRvLgoKQSBGaWd1cmEgYWJhaXhvIG1vc3RyYSBlc3NlIHByb2Nlc3NvIGFwbGljYWRvIGVtIHVtIHByb2JsZW1hIGRlIGNsYXNzaWZpY2HDp8OjbyBkZSBkYWRvcywgbmVzc2UgdGlwbyBkZSBwcm9ibGVtYSBhIHTDqWNuaWNhIGRlIG1heGltaXphw6fDo28gw6kgYXBsaWNhZGEgZGVudHJvIGRlIGNhZGEgY2xhc3NlIHNlcGFyYWRhbWVudGUsIG5lc3NlIGV4ZW1wbG8gbsOjbyBmb2kgdXNhZGEgYSBtw6lkaWEgZW50cmUgZ3J1cG9zIG1hcyBzaW0gbyBtw61uaW1vLgoKIVtNYXhpbWl6YcOnw6NvIGRlIGRpc3NpbWlsYXJpZGFkZSBwYXJhIGNsYXNzaWZpY2HDp8Ojb10oLi9DaDA0RmlnMDUucG5nKQoKIyNUw6ljbmljYXMgZGUgcmVhbW9zdHJhZ2VtCkRlIHVtYSBtYW5laXJhIGdlcmFsIHTDqWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gdXNhZGFzIHBhcmEgYXZhbGlhciBhIHBlcmZvcm1hbmNlIGRvIG1vZGVsbyB0cmFiYWxoYW0gZGUgZm9ybWEgcGFyZWNpZGEuIFVtYSBwYXJ0ZSBkb3MgZGFkb3Mgw6kgdXNhZGEgcGFyYSBmaXRhciBvIG1vZGVsbyBlIGEgb3V0cmEgw6kgdXNhZGEgcGFyYSB0ZXN0YXIgYSBlZmljw6FjaWEgZG9zIGRhZG9zLCBlc3NlIHByb2Nlc3NvIMOpIHJlcGV0aWRvIGRpdmVyc2FzIHZlemVzIG9zIHJlc3VsdGFkb3Mgc8OjbyBzdW1hcml6YWRvcyBlIGFncmVnYWRvcy4gQSBkaWZlcmVuw6dhIGRhcyB0ZWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gcmVzaWRlbSBuYSBmb3JtYSBjb21vIGFzIHN1YmFtb3N0cmFzIHPDo28gc2VsZWNpb25hZG9zLgoKCiMjI2stRm9sZCBDcm9zcy12YWxpZGF0aW9uCkFzIGluc3TDom5jaWFzIHPDo28gZGl2aWRpZGFzIGVtICprKiBwYXJ0acOnw7VlcyBjb20gdGFtYW5ob3MgYXByb3hpbWFkb3MsIHVtIG1vZGVsbyDDqSBmaXRhZG8gdXNhbmRvIDkgcGFydGnDp8O1ZXMgZSB0ZXN0YWRvIGNvbSBhIMO6bHRpbWEuIEVzc2UgcHJvY2Vzc28gw6kgcmVwZXRpZG8gMTAgdmV6ZXMgdHJvY2FuZG8gYSBwYXJ0acOnw6NvIGRlIHRlc3RlIHBvciB1bWEgcXVlIG51bmNhIGZvaSB1c2FkYSBwYXJhIHRlc3RlLCBuYSBmaWd1cmEgYWJhaXhvIG5vdGFtb3MgdW0gMy1mb2xkIGNyb3NzLXZhbGlkYXRpb246CiFbQm9vdHN0cmFwXSguL0NoMDRGaWcwNi5wbmcpClVtYSB2YXJpYcOnw6NvIGRlc3NhIGVzdHJhdMOpZ2lhIMOpIGZhemVyIHVtYSBhbW9zdHJhZ2VtIGVzdHJhdMOtZmljYWRhIHBvciBjbGFzc2VzIGVtIGNhZGEgdW0gZG9zIGZvbGRzLiBPdXRyYSB2YXJpYcOnw6NvLCBsZWF2ZSBvbmUgb3V0IGNyb3NzLXZhbGlkYXRpb24gKExPT0NWKSwgw6kgdW0gY2FzbyBlc3BlY2lhbCBvbmRlIGsgw6kgaWd1YWwgYW8gbsO6bWVybyBkZSBpbnN0w6JuY2lhcywgcmVtb3ZlbW9zIHVtYSBlIHRyZWluYW1vcyBjb20gYXMgb3V0cmFzLiBPIG1vZGVsbyBmaW5hbCDDqSBjYWxjdWxhZG8gcGVsYSBzdW1hcml6YcOnw6NvIGRhcyBrIGluc3TDom5jaWFzIGRlaXhhZGFzIGRlIGZvcmEgdW1hIGEgdW1hLgoKTsOjbyBow6EgZGVmaW5pw6fDo28gZm9ybWFsIHNvYnJlIHF1YWwgbyBtZWxob3IgdmFsb3IgZGUgKmsqIHRpcGljYW1lbnRlIHPDo28gdXNhZG9zIG9zIHZhbG9yZXMgJHs1LCAxMH0kIHF1YW50byBtYWlvciBvIHZhbG9yIGRlICprKiBtZW5vciBvIGJpYXMgZGEgdMOpY25pY2EuIENvbSBvIGF1bWVudG8gZGUgKmsqIGEgZGlmZXJlbsOnYSBlbnRyZSBjb25qdW50b3MgZGUgdHJlaW5vIGUgdGVzdGUgcmVkdXouCgpVbSBwb250byBpbXBvcnRhbnRlIHNvYnJlIHTDqWNuaWNhcyBkZSByZWFtb3N0cmFnZW0gw6kgaW5jZXJ0ZXphICh2YXJpYcOnw6NvL3J1w61kbyksIHVtIG3DqXRvZG8gc2VtIHZpw6lzIHBvZGUgcHJlZGl6ZXIgbyB2YWxvciBjb3JyZXRvIG1hcyBwYWdhIHVtIHByZcOnbyBhbHRvIHBhcmEgaXNzbywgKmluY2VydGV6YSouIE8gcXVlIHNpZ25pZmljYSBxdWUgcmVwZXRpciBvIHByb2Nlc3NvIGRlIHJlIGFtb3N0cmFnZW0gcG9kZSBwcm9kdXppciByZXN1bHRhZG9zIGRpc3RpbnRvcy4gVmFsaWRhw6fDo28gY3J1emFkYSBwb3NzdcOtIGFsdGEgdmFyaWHDp8OjbyBjb21wYXJhZGEgYSBvdXRyYXMgdMOpY25pY2FzLCBwb3LDqW0gcGFyYSBncmFuZGVzIGNvbmp1bnRvcyBkZSB0cmVpbm8gZXNzYSB2YXJpw6JuY2lhIHBvZGUgc2VyIGRlc3ByZXphZGEuCgpWYWxvcmVzIGdyYW5kZXMgZGUgayBzw6NvIGNvbXB1dGFjaW9uYWxtZW50ZSBvbmVyb3NvcywgTE9PQ1Ygw6kgbyBtYWlzIGNvbXB1dGFjaW9uYWxtZW50ZSBpbnRlbnNvIGRlbnRyZSB0b2RhcyBhcyB0w6ljbmljYXMgcG9pcyBuZWNlc3NpdGEgZGUgdW0gbW9kZWxvIGRpc3RpbnRvIHBhcmEgY2FkYSBwb250byBlIGNhZGEgc3ViY29uanVudG8gdGVtIG8gdGFtYW5obyBkYSBhbW9zdHJhIG1lbm9zIHVtLiBUZW0gcGVzcXVpc2FzIHF1ZSBtb3N0cmFtIHF1ZSBvIGxlYXZlIG9uZSBvdXQgw6kgdMOjbyBlZmV0aXZvIHF1YW50byB1bWEgdmFsaWRhw6fDo28gY3J1emFkYSBwYXJhICRrPTEwJC4gVmFsb3JlcyBwZXF1ZW5vcyBkZSAqayogdGVtIHVtIGJpYXMgYWx0byBtYXMgc8OjbyBtZW5vcyBjb21wdXRhY2lvbmFsbWVudGUgb25lcm9zb3MsIGVzc2UgYmlhcyDDqSBxdWFzZSBvIG1lc21vIG9idGlkbyBwb3IgdW0gYm9vdHN0cmFwIHBvcsOpbSBjb20gdW1hIHZhcmnDom5jaWEgbXVpdG8gbWFpb3IuCgoKIyMjR2VuZXJhbGl6YWUgQ3Jvc3MtdmFsaWRhdGlvbgpQYXJhIG1vZGVsb3MgbGluZWFyZXMgZGUgcmVncmVzc8OjbyBwYXJhIGFwcm94aW1hciBvIGVycm8gZG8gbGVhdmUtb25lLW91dC4gTyBnZW5lcmFsaXplZCBDcm9zcy12YWxpZGF0aW9uIChHQ1YpIGVzdGF0w61zdGljYSBuw6NvIGV4aWdlIHJlZml0YXIgbyBtb2RlbG8gcGFyYSBjYWRhIHN1YmFtb3N0cmEKJCQKR0NWID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV57bn0gIFxmcmFje3lfaSAtIFxoYXR7eV9pfX17MSAtIFxmcmFje2RmfXtufX0gCiQkCm9uZGUgJHlfaSQgw6kgbyBpLcOpc2ltbyByw7N0dWxvLCAkXGhhdHt5X2l9JCDDqSBhIGktw6lzaW1hIHByZWRpw6fDo28gZG8gbW9kZWxvIGUgJGRmJCBzw6NvIG9zIGdyYXVzIGRlIGxpYmVyZGFkZSBkbyBtb2RlbG8gKHBhcsOibWV0cm9zIGVzdGltYWRvcyBwZWxvIG1lc21vKSBxdWUgw6kgdW1hIG1lZGlkYSBkZSBjb21wbGV4aWRhZGUgcGFyYSBtb2RlbG9zIGxpbmVhcmVzLiBEb2lzIG1vZGVsb3MgY29tIGEgbWVzbWEgc29tYSBkZSBlcnJvIHF1YWRyYWRvIHRlcsOjbyBkaWZlcmVudGVzIEdDViBzZSBhIGNvbXBsZXhpZGFkZSBkb3MgbW9kZWxvcyBmb3JlbSBkaXN0aW50YXMuIFZhbGUgcmVzc2FsdGFyIHF1ZSDDqSB1bWEgZsOzcm11bGEgZmVjaGFkYS4KCiMjI1JlcGVhdGVkIFRyYWluaW5nL1Rlc3QgU3BsaXRzCsOJIGNvbmhlY2lkbyBwb3IgbGVhdmUtZ3JvdXAtb3V0IGNyb3NzLXZhbGlkYXRpb24sIG1vbnRlIGNhcmxvIGNyb3NzLXZhbGlkYXRpb24sIGNyaWEgbXVpdGFzIGRpdmlzw7VlcyBkb3MgZGFkb3MgZGUgdHJlaW5vIGUgdGVzdGUsIGEgcHJvcG9yw6fDo28gZGUgZGFkb3MgcGFyYSBjYWRhIHN1YmFtb3N0cmEgZSBvIG7Dum1lcm8gZGUgcmVwZXRpw6fDtWVzIHPDo28gY29udHJvbGFkb3MgcGVsbyBhbmFsaXN0YS4gQ29tbyBmYWxhbW9zIGFudGVyaW9ybWVudGUsIG8gYmlhcyByZWR1eiBjb25mb3JtZSBhIHF1YW50aWRhZGUgZGUgZGFkb3MgbmEgYW1vc3RyYSBzZSBhcHJveGltYSBkbyBjb25qdW50byBkZSBtb2RlbGFnZW0gdmFsb3JlcyB0aXBpY2FtZW50ZSB1c2Fkb3Mgc8OjbzogNzUlIC0gODAlIC4gQSBmaWd1cmEgYWJhaXhvIGV4ZW1wbGlmaWNhIGVzc2UgZXNxdWVtYToKIVtSZXBlYXRlZCBUcmFpbmluZy9UZXN0IFNwbGl0c10oLi9DaDA0RmlnMDcucG5nKQoKUG9kZS1zZSBvYnNlcnZhciBxdWUgYSBkaWZlcmVuw6dhIGZ1bmRhbWVudGFsIGVudHJlIGVzc2EgZXN0cmF0w6lnaWEgZSBhIHZhbGlkYcOnw6NvIGNydXphZGEgw6kgcXVlIHBvZGUgaGF2ZXIgcmVwZXRpw6fDo28gZGUgaW5zdMOibmNpYXMgcG9kZW0gc2VyIHJlcHJlc2VudGFkYXMgZW0gdsOhcmlvcyBncnVwb3MgZGVpeGFkb3MgcGFyYSBwcmVkaXplci4gQWzDqW0gZGlzc28gbyBuw7ptZXJvIGRlIHJlcGV0acOnw7VlcyBhcXVpIHRlbmRlIGEgc2VyIG11aXRvIG1haW9yIHF1ZSB1bWEgdmFsaWRhw6fDo28gY3J1emFkYS4KCk8gbsO6bWVybyBlIHJlcGV0acOnw7VlcyDDqSBpbXBvcnRhbnRlIHBvaXMgYW8gYXVtZW50YXJtb3MgZWxlIGRlY3JlbWVudGFtb3MgYSBpbmNlcnRlemEgZG8gbW9kZWxvLiBQYXJhIHJlc3VsdGFkb3MgY29tIGFsdGEgaW5zdGFiaWxpZGFkZSAyMCByZXBldGnDp8O1ZXMgc2VyaWFtIHN1ZmljaWVudGVzLCBwYXJhIG9idGVyIHVtIHNjb3JlIG1haXMgZXN0w6F2ZWwgcG9kZW1vcyBjb2xvY2FyIDUwLTIwMCByZXBldGnDp8O1ZXMuIEVzc2UgdmFsb3Igw6kgdW1hIHByb3BvcsOnw6NvIGRvcyBleGVtcGxvcyBzZW5kbyBhbG9jYWRvcyBubyBjb25qdW50byBkZSBwcmVkacOnw6NvLCBxdWFudG8gbWFpb3IgYSBwb3JjZW50YWdlbSAgbWFpcyByZXBldGnDp8O1ZXMgc2Vyw6NvIG5lY2Vzc8OhcmlhcyBwYXJhIHJlZHV6aXIgYSBpbmNlcnRlemEgZG8gbW9kZWxvCgoKIyMjQm9vdHN0cmFwCsOJIHVtYSBhbW9zdHJhZ2VtIGNvbSByZXBvc2nDp8Ojbywgb3Ugc2VqYSwgYXDDs3MgdW0gcG9udG8gc2VyIHNlbGVjaW9uYWRvIHBhcmEgbyBmb2xkL3NldCBlbGUgYWluZGEgZmljYSBkaXNwb27DrXZlbCBwYXJhIHNlciByZXNlbGVjaW9uYWRvIG5vdmFtZW50ZS4gVW1hIGFtb3N0cmEgZGUgYm9vdHN0cmFwIHRlbSBvIG1lc21vIHRhbWFuaG8gZG8gZGF0YXNldCBvcmlnaW5hbCwgY29tbyByZXN1bHRhZG8gZGlyZXRvIGFsZ3VucyBwb250b3Mgc2Vyw6NvIHNlbGVjaW9uYWRvcyBtYWlzIGRlIHVtYSB2ZXogZSBvdXRyb3MgbsOjbyBzZXLDo28gc2VsZWNpb25hZG9zLiBPcyBwb250b3MgbsOjbyBzZWxlY2lvbmFkb3Mgc8OjbyBjb25oZWNpZG9zIHBvciAqb3V0LW9mLWJhZyosIHVtYSBpdGVyYcOnw6NvIGRlIGJvb3RzdHJhcCB1c2Egb3MgZXhlbXBsb3Mgc2VsZWNpb25hZG9zIHBhcmEgdHJlaW5hciBvIG1vZGVsbyBlIG9zICpvdXQtb2YtYmFnKiBwYXJhIHRlc3Rhci4gTmEgZmlndXJhIGFiYWl4byBwb2RlbW9zIHZlciB1bSBleGVtcGxvIGRpc3NvOgoKIVtCb290c3RyYXBdKC4vQ2gwNEZpZzA4LnBuZykKCkRlIHVtYSBmb3JtYSBnZXJhbCBhcyB0YXhhcyBkZSBlcnJvIGRlIGJvb3RzdHJhcCB0ZW0gbWVub3MgaW5jZXJ0ZXphIHF1ZSB1bSBrLWZvbGQsIGVudHJldGFudG8gJDYzLjI1XCUkIGRvcyBwb250b3Mgc8OjbyByZXByZXNlbnRhZG9zIHBlbG8gbWVub3MgdW1hIHZleiwgcG9ydGFudG8gZXNzYSB0w6ljbmljYSB0ZW0gdW0gYmlhcyBzaW1pbGFyIGFvIGstZm9sZCBwYXJhICRrPTIkLiBTZSBvIGNvbmp1bnRvIGRlIHRyZWlubyBmb3IgcGVxdWVubyBlc3NlIGJpYXMgw6kgZ3JhbmRlIGNhc28gY29udHLDoXJpbyBwb2RlIHNlciBkZXNwcmV6YWRvLgoK